package com.gcloud.mesh.asset.timer;

import java.util.List;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import com.gcloud.mesh.asset.enums.DeviceType;
import com.gcloud.mesh.asset.enums.XbrotherDefaultDeviceType;
import com.gcloud.mesh.asset.enums.XbrotherDeviceType;
import com.gcloud.mesh.asset.service.IAssetService;
import com.gcloud.mesh.framework.core.web.handle.ErrorCodeMapper;
import com.gcloud.mesh.header.msg.asset.CreateDeviceMsg;
import com.gcloud.mesh.header.msg.asset.ListDeviceMsg;
import com.gcloud.mesh.header.msg.asset.UpdateDeviceMsg;
import com.gcloud.mesh.header.vo.asset.DeviceItemVo;
import com.gcloud.mesh.header.vo.supplier.XbortherAssetItemVo;
import com.gcloud.mesh.header.vo.supplier.XbrotherSupervisionSystemVo;
import com.gcloud.mesh.supplier.entity.SupplierEntity;
import com.gcloud.mesh.supplier.sdk.XbrotherSupervisionSystemSdk;
import com.gcloud.mesh.supplier.service.SupplierService;
import com.gcloud.mesh.utils.SupplierSystemTypeUtil;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Component
//@ConditionalOnProperty(name = "asset.supervision_system", havingValue = "xbrother")
public class XbrotherSupervisionSystemTimer {
	
	private static final String SYSTEM_TYPE = "xbrother";
	
	private static final String TYPE = "supervision_system";
	
	private static final String GENERAL = "general";
	
	@Autowired
    private ErrorCodeMapper errorCodeMapper;
	
	@Autowired
	private SupplierService supplierService;
	
	@Autowired
	private IAssetService assetService;

	@Scheduled(initialDelay = 0, fixedDelay = 15 * 1000)
	private void execute() {
		List<SupplierEntity> suppliers = supplierService.listByType(TYPE);
		
		for(SupplierEntity supplier: suppliers) {
			new Thread(new Runnable() {
				@Override
				public void run() {
					// TODO Auto-generated method stub
					XbrotherSupervisionSystemVo obj = (XbrotherSupervisionSystemVo)SupplierSystemTypeUtil.getByName(supplier.getType(), supplier.getConfig());
					if(obj != null) {
						XbrotherSupervisionSystemSdk sdk = XbrotherSupervisionSystemSdk.getInstance(obj.getHostIp(), obj.getLoginCode());
//						XbrotherSupervisionSystemSdk sdk = new XbrotherSupervisionSystemSdk(obj.getHostIp(), obj.getLoginCode());
						if(sdk != null) {
							List<XbortherAssetItemVo> items = sdk.listAssets();
							compareAndUpdate(items, supplier.getDatacenterId(), supplier.getId());
						}
					}
				}
				
			}).start();
		}
	}
	
	private void compareAndUpdate(List<XbortherAssetItemVo> items, String datacenterId, String supplierId) {
		for(XbortherAssetItemVo vo: items) {

			synchronized(XbrotherSupervisionSystemTimer.class) {
				DeviceItemVo device = assetService.getDeviceByDeviceId(vo.getResource_id());
				if(device == null) {
					saveDevice(vo, datacenterId, supplierId);
				}else {
					updateDevice(vo, device, datacenterId);
				}
			}
		}
		//syncSupplier(items, supplierId);
	}
	
	private void saveDevice(XbortherAssetItemVo vo, String datacenterId, String supplierId) {
		CreateDeviceMsg msg = new CreateDeviceMsg();
		msg.setName(vo.getName());
		if(XbrotherDefaultDeviceType.getDeviceTypeByCnName(vo.getName()) != null) {
			msg.setType(XbrotherDefaultDeviceType.getDeviceTypeByCnName(vo.getName()).getDeviceType().getNo());
		} else {
			if(XbrotherDeviceType.getDeviceTypeByCnName(vo.getDevice_info()) != null) {
				msg.setType(XbrotherDeviceType.getDeviceTypeByCnName(vo.getDevice_info()).getDeviceType().getNo());
			} else {
				msg.setType(DeviceType.GENERAL.getNo());
			}
			
		}
		msg.setDeviceManufacturer(GENERAL);
		msg.setDeviceModel(GENERAL);
		msg.setEsn(GENERAL);
		msg.setDatacenterId(datacenterId);
		msg.setFrom(supplierId);
		msg.setDeviceId(vo.getResource_id());
		try {
			assetService.createDevice(msg, null);
		} catch(Exception e) {
			log.error("{} save deivce : {}[{}] {}",
					XbrotherSupervisionSystemTimer.class.getName(), msg.getName(), msg.getDeviceId(), 
					errorCodeMapper.getErrorMsg(e.getMessage()));
		}
		
	}
	
	private void updateDevice(XbortherAssetItemVo vo, DeviceItemVo device, String datacenterId) {
		UpdateDeviceMsg msg = new UpdateDeviceMsg();
		boolean updateFlag = false;
		if(!device.getName().equals(vo.getName())) {
			msg.setName(vo.getName());
			msg.setId(device.getId());
			updateFlag = true;
		}
		if(updateFlag) {
			try {
				assetService.updateDevice(msg, null);
			} catch(Exception e) {
				log.error("{} update device : {}[{}] {}", 
						XbrotherSupervisionSystemTimer.class.getName(), device.getName(), device.getDeviceId(), 
						errorCodeMapper.getErrorMsg(e.getMessage()));
			}
		}
		
		
	}
	
	private void syncSupplier(List<XbortherAssetItemVo> items, String supplierId) {
		ListDeviceMsg msg = new ListDeviceMsg();
		msg.setFrom(supplierId);
		List<DeviceItemVo> exists = assetService.listDevice(msg);
		List<String> nowDeviceIds = items.stream().map( s -> s.getResource_id()).distinct().collect(Collectors.toList());
		List<String> existsDeviceIds = exists.stream().map( s -> s.getDeviceId()).distinct().collect(Collectors.toList());
		List<String> deletedDeviceIds = existsDeviceIds.stream().filter( s -> !nowDeviceIds.contains(s)).collect(Collectors.toList());
		List<DeviceItemVo> deletedDevices = exists.stream().filter( s -> deletedDeviceIds.contains(s.getDeviceId())).collect(Collectors.toList());
		for(DeviceItemVo device: deletedDevices) {
			try {
				assetService.deleteDevice(device.getId(), null);
			} catch(Exception e) {
				log.error("{} delete device :{}", XbrotherSupervisionSystemTimer.class.getName(), errorCodeMapper.getErrorMsg(e.getMessage()));
			}
			
		}
	}
	
}
